﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Apache.Cassandra;
using SKBKontur.Logging.Model;
using SKBKontur.Serialization;

namespace SKBKontur.Cassandra.Logging.KeyGeneration
{
    public class LogEventBuilder
    {
        public override int GetHashCode()
        {
            unchecked
            {
                return Key.Aggregate(23, (current, b) => current*17 + b);
            }
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;
            if (obj is LogEventBuilder)
            {
                byte[] otherKey = ((LogEventBuilder) obj).Key;
                return Key.Length == otherKey.Length && !Key.Where((t, i) => t != otherKey[i]).Any();
            }
            return false;
        }

        public byte[] Key { get; private set; }
        private Dictionary<string, byte[]> eventColumns;
        private Dictionary<string, byte[]> exceptionColumns;

        public static LogEventBuilder CreateWithEventData(byte [] key, List<ColumnOrSuperColumn> eventColumns)
        {
            var result = new LogEventBuilder(key);
            result.SetEvent(eventColumns);
            return result;
        }

        public static LogEventBuilder CreateWithExceptionData(byte[] key, List<ColumnOrSuperColumn> exceptionColumns)
        {
            var result = new LogEventBuilder(key);
            result.SetException(exceptionColumns);
            return result;
        }

        public static LogEventBuilder Merge(LogEventBuilder a, LogEventBuilder b)
        {
            return new LogEventBuilder(a.Key)
                       {
                           eventColumns = a.eventColumns ?? b.eventColumns,
                           exceptionColumns = a.exceptionColumns ?? b.exceptionColumns
                       };
        }

        public LogEventBuilder(byte[] key)
        {
            Key = key;
        }

        public void SetEvent(List<ColumnOrSuperColumn> eventColumns)
        {
            this.eventColumns = new Dictionary<string, byte[]>();
            foreach (var column in eventColumns)
                this.eventColumns[Encoding.UTF8.GetString(column.Column.Name)] = column.Column.Value;
        }

        public void SetException(List<ColumnOrSuperColumn> exceptionColumns)
        {
            this.exceptionColumns = new Dictionary<string, byte[]>();
            foreach (var column in exceptionColumns)
                this.exceptionColumns[Encoding.UTF8.GetString(column.Column.Name)] = column.Column.Value;
        }

        public T Build<T>(IStringToByteArraySerializer serializer) where T: LogEvent, new()
        {
            var result = new T();
            if (exceptionColumns != null)
            {
                var exception = new LogException();
                serializer.DeserializeTo(ref exception, exceptionColumns);
                result.LogException = exception;
            }
            serializer.DeserializeTo(ref result, eventColumns);
            return result;
        }
    }
}
